package com.jade.bss.ec.ware.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.ejb.TransactionAttribute;
import javax.inject.Inject;
import javax.inject.Named;

import com.jade.bss.base.BssConstants;
import com.jade.bss.base.brand.Brand;
import com.jade.bss.base.brand.BrandManager;
import com.jade.bss.base.category.Category;
import com.jade.bss.base.category.CategoryManager;
import com.jade.bss.base.journal.OperationJournal;
import com.jade.bss.ec.ware.*;
import com.jade.framework.base.criterion.Criteria;
import com.jade.framework.base.criterion.Restrictions;
import com.jade.framework.base.util.PagingList;
import com.jade.journal.Journal;
import com.jade.journal.JournalUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;

/**
 * 商品管理器实现。
 */
@Named ("bss_wareManager")
public class WareManagerImpl
        implements WareManager
{
    private WareDao wareDao;
    private WareImageManager imageManager;
    private BrandManager brandManager;
    private CategoryManager categoryManager;

    @Inject
    public void setWareDao(@Named ("bss_wareDao") WareDao wareDao)
    {
        this.wareDao = wareDao;
    }


    @Inject
    public void setImageManager(@Named ("bss_wareImageManager") WareImageManager imageManager)
    {
        this.imageManager = imageManager;
    }

    @Inject
    public void setBrandManager(@Named ("bss_brandManager") BrandManager brandManager)
    {
        this.brandManager = brandManager;
    }

    @Inject
    public void setCategoryManager(@Named ("bss_categoryManager") CategoryManager categoryManager)
    {
        this.categoryManager = categoryManager;
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public void createWare(Ware ware)
            throws WareException
    {
        //设置商品基本信息
        Date now = new Date();

        ware.setCreationDate(now);
        ware.setUpdateDate(now);
        ware.setStatus(Ware.STATUS_NEW);
        if (StringUtils.isBlank(ware.getOwnerType())) {
            ware.setOwnerType(BssConstants.OWNER_TYPE_SYSTEM);
        }
        if (StringUtils.isNotBlank(ware.getOwnerId())) {
            ware.setOwnerId(BssConstants.OWNER_ID_SYSTEM);
        }
        //保存商品信息
        wareDao.addWare(ware);
        //添加商品图片
        List<WareImage> images = ware.getImages();
        if (images != null && !images.isEmpty()) {
            for (WareImage image : images) {
                image.setWareId(ware.getId());
                image.setColorSpec(0);
                imageManager.addImage(image);
            }
        }
        //添加商品SKU
        List<WareSku> skus = ware.getSkus();
        if (skus != null && !skus.isEmpty()) {
            for (WareSku sku : skus) {
                sku.setWareId(ware.getId());
                addSku(sku);
            }
        }
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public void updateWare(Ware ware)
            throws WareException
    {
        //判断商品的状态
        Ware old = getWare(ware.getId());
        if (old == null) {
            throw new WareException("err.bss.ware.not_existed", "Ware not existed", null, ware.getId());
        }
        if (old.getStatus() == Ware.STATUS_ON_SALE) {
            throw new WareException("err.bss.ware.invalid_status", "Invalid ware status", null, ware.getId(),
                    ware.getStatus());
        }
        ware.setStatus(ware.getStatus());
        Date now = new Date();
        ware.setUpdateDate(now);
        //保存商品信息
        wareDao.addWare(ware);
        //处理商品图片
        //删除原先所有图片
        imageManager.removeImage(0, ware.getId());
        //新增新的图片
        List<WareImage> images = ware.getImages();
        if (images != null && !images.isEmpty()) {
            for (WareImage image : images) {
                image.setWareId(ware.getId());
                image.setColorSpec(0);
                imageManager.addImage(image);
            }
        }
        //更新商品SKU
        for (WareSku sku : ware.getSkus()) {
            if (sku.getId() == 0) {
                sku.setWareId(ware.getId());
                addSku(sku);
            } else {
                sku.setWareId(ware.getId());
                updateSku(sku);
            }
        }
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public void putOnWare(long... wareIds)
            throws WareException
    {
        for (long wareId : wareIds) {
            Ware ware = getWare(wareId);
            if (ware == null) {
                continue;
            }
            if (ware.getStatus() == Ware.STATUS_ON_SALE) {
                throw new WareException("err.bss.ware.already_on_sale", "Ware is already on sale", null, ware.getId());
            }
            ware.setStatus(Ware.STATUS_ON_SALE);
            ware.setUpdateDate(new Date());
            ware.setSaleDate(ware.getUpdateDate());
            wareDao.updateWare(ware);

        }
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public void pullOffWare(long... wareIds)
            throws WareException
    {
        for (long wareId : wareIds) {
            Ware ware = getWare(wareId);
            if (ware == null) {
                continue;
            }
            if (ware.getStatus() != Ware.STATUS_ON_SALE) {
                throw new WareException("err.bss.ware.already_off_sale", "Ware is already off sale", null,
                        ware.getId());
            }
            ware.setStatus(Ware.STATUS_OFF_SALE);
            ware.setUpdateDate(new Date());
            ware.setSaleDate(ware.getUpdateDate());
            wareDao.updateWare(ware);

        }

    }

    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public void removeWare(long... wareIds)
            throws WareException
    {
        for (long wareId : wareIds) {
            Ware ware = getWare(wareId);
            if (ware == null) {
                continue;
            }
            if (ware.getStatus() != Ware.STATUS_ON_SALE) {
                throw new WareException("err.bss.ware.invalid_status", "Ware is on sale", null, ware.getId());
            }
            wareDao.removeWare(ware);
        }
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public void updateWareStock(long wareId, long quantity)
            throws WareException
    {
        Ware ware = getWare(wareId);
        if (ware == null) {
            throw new WareException("err.bss.ware.not_existed", "Ware is not existed", null, ware.getId());
        }
        ware.setStockNum(quantity);
        wareDao.updateWare(ware);

    }

    public Ware getWare(long id)
            throws WareException
    {
        return wareDao.getWare(id);
    }

    public List<Ware> listWare(Criteria criteria)
    {
        return wareDao.listWare(criteria);
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public PagingList<Ware> queryWare(Criteria criteria)
    {
        return wareDao.queryWare(criteria);
    }

    protected void checkWareStatus(long wareId)
            throws WareException
    {
        Ware ware = getWare(wareId);
        if (ware.getStatus() == Ware.STATUS_ON_SALE) {
            throw new WareException("err.bss.ware.invalid_status", "Ware is on sale", null, ware.getId());
        }
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public void addSku(WareSku sku)
            throws WareException
    {
        //上架商品不能修改，验证商品状态
        checkWareStatus(sku.getWareId());
        wareDao.addSku(sku);
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public void updateSku(WareSku sku)
            throws WareException
    {
        //上架商品不能修改，验证商品状态
        checkWareStatus(sku.getWareId());
        wareDao.updateSku(sku);
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public void updateSkuStock(long skuId, long quantity)
            throws WareException
    {
        WareSku sku = getSku(skuId);
        sku.setStockNum(quantity);
        updateSku(sku);
    }

    @TransactionAttribute
    @Transactional (rollbackFor = Throwable.class)
    public void removeSku(long... ids)
            throws WareException
    {
        for (long id : ids) {
            WareSku sku = getSku(id);
            //上架商品不能修改，验证商品状态
            checkWareStatus(sku.getWareId());
            if (sku != null) {
                wareDao.removeSku(sku);
                //删除一个SKU图片不一定需要删除，因为其他SKU可能仍在使用，目前图片仅仅与color规格相关
            }
        }
    }

    public WareSku getSku(long id)
    {
        return wareDao.getSku(id);
    }

    public WareSku getSku(long wareId, long colorSpec, long sizeSpec, long otherSpec)
    {
        Criteria criteria = new Criteria(0, 1);
        criteria.add(Restrictions.eq("wareId", wareId));
        criteria.add(Restrictions.eq("colorSpec", colorSpec));
        criteria.add(Restrictions.eq("sizeSpec", sizeSpec));
        criteria.add(Restrictions.eq("otherSpec", otherSpec));
        List<WareSku> skus = wareDao.listSku(criteria);
        return skus.isEmpty() ? null : skus.get(0);
    }

    public List<WareSku> listSku(long wareId)
    {
        Criteria criteria = new Criteria(-1, -1);
        criteria.add(Restrictions.eq("wareId", wareId));
        return wareDao.listSku(criteria);
    }

    public PagingList<WareSku> querySku(Criteria criteria)
    {
        return wareDao.querySku(criteria);
    }

    public List<Brand> searchBrand(Criteria criteria)
    {
        List<Long> ids = wareDao.searchBrand(criteria);
        List<Brand> brands = new ArrayList<Brand>();
        for (long bid : ids) {
            Brand brand = brandManager.get(bid);
            if (brand != null) {
                brands.add(brand);
            }
        }
        return brands;
    }

    public List<Category> searchCategory(Criteria criteria)
    {
        List<Long> ids = wareDao.searchCategory(criteria);
        List<Category> categories = new ArrayList<Category>();
        for (long cid : ids) {
            Category category = categoryManager.get(cid, false);
            if (category != null) {
                categories.add(category);
            }
        }
        return categories;
    }
}
